#! /usr/bin/env python

"""
::BOH
$Id: owtf.py,v 1.0 2007/04/09 00:00:00

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
::EOH

OWTF daemon.

You must be running OWFS and OWserver for this to work.
All temperatures are in degrees C.
"""
import sys, os 
import ownet
import thread
import threading
from time import *
from datetime import *
from Queue import *
from OWTFparser import *
from socket import *

#
# Insert relevant configuration stuff here!
#
storage_q = Queue()
init = HandleXML()
config = ConfScanner(init.ParseFromFile("unified_configuration.txt"))
config.servers
config.sensors

if config.general_verbose:
    buf = 1024
    addr = (config.general_verbose_host,config.general_verbose_port)
    UDPSock = socket( AF_INET,SOCK_DGRAM )

if config.general_db[0].strip()== 'mysql':#IF Using MySQL
    try:
        import MySQLdb
    except:
        pass
else:#IF Using SQLite
    try:
        if sys.version_info[1] > 4:
            import sqlite3
        else:
            from pysqlite2 import dbapi2 as sqlite
    except:
        pass

if config.legacy:
    import pickle
if config.legacy or config.remote:
    from socket import *

def GenSensorDict(l):
    d = {}
    for x in l:
        d[x[0]] = x[1]
    return d

def GenServerDict(l):
    d = {}
    for x in l:
        d[x[0]] = x[2]
    return d

sensor_dict = GenSensorDict(config.sensors)
server_dict = GenServerDict(config.servers)

#
"""
START ALERT Functions
"""
#
def Temp_gen_alert(temp,t_min = 5, t_max = 35):
    """
    Default temp. values are: 
      t_min = 5 (41 F) 
      t_max = 35 (95 F)
    These are based off of the environmental 
    params of an IBM ThinkPad T43 laptop.
    
    This function returns a tuple.
    """
    alert = None
    level = None
    if (temp >= -30) and (temp <= 85):
        if (temp <= (t_min + 3)) and (temp > (t_min + 1.5)):
            level = "1"
            alert = "1001"
        elif (temp >= (t_max - 3)) and (temp < (t_max - 1.5)):
            level = "1"
            alert = "1011"
        elif (temp <= (t_min + 1.5)) and (temp >= t_min):
            level = "2"
            alert = "1002"
        elif (temp >= (t_max - 1.5)) and (temp <= t_max):
            level = "2"
            alert = "1012"
        elif (temp < t_min):
            level = "3"
            alert = "1003"
        elif (temp > t_max):
            level = "3"
            alert = "1013"
        else:
            level = None
            alert = None
    else:
        level = "0"
        alert = "0666"
    
    return level, alert

def Humid_gen_alert(humid, h_min = 10, h_max = 85):
    """
    Default humid. values are:
      h_min = 10
      h_max = 85
    These are based off of the environmental 
    params of a Cisco Catalyst WS-C3750G-24TS-E 10/100/1000 switch.
    
    This function returns a tuple.
    """
    alert = None 
    level = None
    
    if (humid > 0):
        if (humid > (h_min + 3)) and (humid <= (h_min + 5)):
            level = "1"
            alert = "2001"
        elif (humid <= (h_max - 3)) and (humid >= (h_max - 5)):
            level = "1"
            alert = "2011"
        elif (humid <= (h_min + 3)) and (humid >= h_min):
            level = "2"
            alert = "2002"
        elif (humid >= (h_max - 3)) and (humid <= h_max):
            level = "2"
            alert = "2012"
        elif (humid < h_min):
            level = "3"
            alert = "2003"
        elif (humid > h_max) and (humid < 100):
            level = "3"
            alert = "2013"
        elif (humid == 100):
            level = "3"
            alert = "2H20"
        elif (humid > 100):
            level = "0"
            alert = "0H20"
        else:
            # If Humid > 0 and not alertable
            level = None
            alert = None
    else:
        # Humid <= 0
        level = None
        alert = None
    
    return level, alert

def V1_gen_alert(v1, v1_min, v1_max):
    alert = None 
    level = None
    
    if v1_min == v1_max:
        level = None
        alert = None
    elif v1 < v1_min:
        level = "3"
        alert = "3003"
    elif v1 > v1_max:
        level = "3"
        alert = "3013"
    elif v1 == v1_min:
        level = "2"
        alert = "3002"
    elif v1 == v1_max:
        level = "2"
        alert = "3012"
    
    else:
        level = None
        alert = None
    return level, alert

def V2_gen_alert(v2, v2_min, v2_max):
    alert = None 
    level = None
    
    if v2_min == v2_max:
        level = None
        alert = None
    elif v2 < v2_min:
        level = "3"
        alert = "4003"
    elif v2 > v2_max:
        level = "3"
        alert = "4013"
    elif v2 == v2_min:
        level = "2"
        alert = "4002"
    elif v2 == v2_max:
        level = "2"
        alert = "4012"
    else:
        level = None
        alert = None
    return level, alert

def Alert_msg_gen(sid,location,alert):
    sl = "Sensor %s, located at %s," %(sid, location)
    msg_gen_dict = {"0404":"has gone inactive.","0666":"has output a really invalid temperature value",
        "0H20":"has output a really invalid humidity value","1001":"is nearing the minimum temperature limit.",
        "1011":"is nearing the maximum temperature limit.","1002":"is at the minimum temperature.",
        "1012":"is at the maximum temperature.","1003":"is below the minimum temperature!",
        "1013":"is above the maximum temperature!","2001":"is nearing the minimum humidity limit.",
        "2011":"is nearing the maximum humidity limit.","2002":"is at the minimum humidity limit.",
        "2012":"is at the maximum humidity limit.","2003":"is below the minimum humidity limit!",
        "2013":"is above the maximum humidity limit!","3003":"is below the minimum V1 limit!",
        "3013":"is above the maximum V1 limit!","4003":"is below the minimum V2 limit!",
        "4013":"is above the maximum V2 limit!","2H20":"is either at 100% humidity or under water!"
    }
    if msg_gen_dict.has_key(alert):
        alert_msg = sl + msg_gen_dict[alert]
    else:
        pass
    return alert_msg
###
"""
END ALERT Functions
"""
###
def owtfMonitor(var_host, var_port):
    r = ownet.Sensor('/', server = var_host, port = int(var_port))
    e = r.entryList()
    s = r.sensorList()

#print 'r:', r
#print 'r.entryList():', e
#print 'r.sensorList():', s
    global storage_q
    global config
    global sensor_dict # may be problematic!
    global server_dict # may be problematic!
    for x in r.sensors():
        reading = Reading()
        tm = datetime.today().strftime( "%Y-%m-%d %H:%M:%S" ) # YYYY-MM-DD HH:MM:SS  
        try:
            reading.SetAlias(sensor_dict[x.address])
        except:
            reading.SetAlias("None")
        try:
            reading.SetLocation(server_dict[x.address])
        except:
            reading.SetLocation("None")
        reading.SetTime(datetime.today().strftime( "%Y-%m-%d %H:%M:%S" )) 
        reading.SetSID(x.address)
        reading.SetMID(server_dict[var_host])
        #to be removed
        #print tm, x.address
        
        if hasattr(x, 'MultiSensor'):
            try:
                print x.MultiSensor
                reading.SetMultiSensor(x.MultiSensor)
            except:
                pass
        if hasattr(x,"type"):
            try:
                print x.type
                reading.SetType(x.type)
            except:
                pass
        if hasattr(x, 'temperature'):
            # -40 C -> +85 C
            try:
                if float(x.temperature) >= -40 and float(x.temperature) <= 85:
                    print x, x.temperature, ((1.8 * x.temperature)+32)
                    reading.SetTemp(x.temperature)
                else:
                    pass
            except:
                pass

        if hasattr(x, 'humidity'):
            # 0% - 100%
            try:
                if float(x.humidity) >= 0.0 and float(x.humidity) <= 100:
                    print x, x.humidity
                    reading.SetHumid(x.humidity)
                else:
                    pass
            except:
                pass

        if hasattr(x, 'VAD'):
            # 1.5 V - 10 V
            try:
                if float(x.VAD) >= 1.5 and float(x.VAD) <= 10:
                    reading.SetV1(x.VAD)
                else:
                    pass
            except:
                pass

        if hasattr(x, 'VDD'):
            # 2.4 V - 10 V
            try:
                if float(x.VDD) >= 2.4 and float(x.VAD) <= 10:
                    reading.SetV2(x.VDD)
                else:
                    pass
            except:
                pass
        storage_q.put(reading)
        if config.general_verbose:
            global UDPSock
            global addr
            UDPSock.sendto( reading.toXML(),addr )
            


#
# EXAMPLE Functions!
#
def runOWTF(y):
    for z in y:
        try:
            owtfMonitor(z[0],z[1])
        except:
            pass
        
def StuffQ(q):
    if not q.empty():
        x = q.get()
        print x.toXML()
    else:
        pass


class newThread(threading.Thread):
    def __init__(self, servers, resolution):
        self.servers = servers
        self.delay = int(resolution)
        threading.Thread.__init__(self)
    def run(self):
        while(1):
            runOWTF(self.servers)
            sleep(self.delay)

class newThread2(threading.Thread):
    def __init__(self, queue):
        self.queue = queue
        threading.Thread.__init__(self)
    def run(self):
        while(1):
            StuffQ(self.queue)

class legacyThread(threading.Thread):
    def __init__(self, host,port):
        threading.Thread.__init__(self)
        self.host = host
        self.port = port

    def run(self):
        global storage_q
        buf = 1024
        addr = (self.host,self.port)
        UDPSock = socket(AF_INET,SOCK_DGRAM)
        UDPSock.bind(addr)
        while(1):
            data,addr = UDPSock.recvfrom(buf)
            if not data:
                pass
            else:
                dout = Reading()
                dout = pickle.loads(data)
                storage_q.put(dout)


thread1 = newThread(config.servers, config.resolution)
thread2 = newThread2(storage_q)

if config.legacy:
    thread3 = legacyThread(config.legacy[0],config.legacy[1])

thread1.start()
thread2.start()
if config.legacy:
    thread3.start()